<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>M3U8 to MP4 Converter</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      padding: 20px;
      box-sizing: border-box;
    }

    .container {
      max-width: 800px;
      margin: auto;
    }

    input[type="text"] {
      width: 100%;
      padding: 10px;
      margin-bottom: 10px;
    }

    button {
      padding: 10px 20px;
      background-color: #007bff;
      color: white;
      border: none;
      cursor: pointer;
    }

    button:hover {
      background-color: #0056b3;
    }

    video {
      width: 100%;
      height: auto;
      margin-top: 20px;
    }

    .list {
      width: 300px;
      position: fixed;
      top: 20px;
      right: 20px;
    }

    .list .item {
      display: flex;
      align-items: center;
      margin-bottom: 10px;
      box-sizing: border-box;
    }

    .list .item .text {
      width: 240px;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    .list .item .btn {
      width: 60px;
      height: 30px;
      line-height: 30px;
      text-align: center;
      background: #007bff;
      color: #fff;
      cursor: pointer;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>M3U8转MP4转换器</h1>
    <div>测试地址：https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8</div>

    <input type="text" id="website" placeholder="输入网站地址" />
    <button onclick="getM3u8OrUrl()">获取网站的m3u8</button>
    <div style="height: 20px"></div>
    <input type="text" id="m3u8-url" placeholder="输入m3u8地址" />
    <button onclick="loadM3U8()">转换</button>
    <button onclick="downloadVideo()" id="download-btn" disabled>下载</button>
    <video id="video-player" controls></video>
  </div>
  <div class="list"></div>
  <iframe id="iframe" src="" frameborder="0" style="display: none"></iframe>

  <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
  <script src="https://cdn.jsdelivr.net/npm/ffmpeg.js@0.26.0/ffmpeg.min.js"></script>
  <script>
    let hls;
    let videoPlayer = document.getElementById("video-player");
    let downloadBtn = document.getElementById("download-btn");

    function getM3u8OrUrl() {
      const website = document.getElementById("website").value;

      // 使用 iframe 获取网站内容
      let iframe = document.getElementById("iframe");
      iframe.src = website;

      // 等待 iframe 加载完毕
      iframe.onload = function () {
        // 获取 iframe 内的 m3u8 地址
        let videoList = iframe.contentDocument.querySelectorAll("video");
        let m3u8 = [];
        let mp4 = [];
        videoList.forEach((el) => {
          if (el.src.indexOf("m3u8") != -1) {
            m3u8.push(el.src);
          } else if (el.src.indexOf("mp4") != -1) {
            mp4.push(el.src);
          }
        });
        let html = "";
        m3u8.forEach((mu38) => {
          html += `
              <div class="item">
                <div class="text">${mu38}</div>
                <div class="btn">复制</div>
              </div>
            `;
        });
        mp4.forEach((mp4) => {
          html += `
              <div class="item">
                <div class="text">${mp4}</div>
                <div class="btn">复制</div>
              </div>
            `;
        });
        let list = document.querySelector(".list");
        list.innerHTML = html;

        let btns = document.querySelectorAll(".btn");
        btns.forEach((btn) => {
          btn.onclick = function () {
            let text = btn.parentNode.querySelector(".text").innerText;
            navigator.clipboard.writeText(text);
          };
        });
      };
    }

    function loadM3U8() {
      const m3u8Url = document.getElementById("m3u8-url").value;
      if (m3u8Url.length <= 0) {
        alert("请输入m3u8地址");
        return;
      }

      if (!Hls.isSupported()) {
        alert("此浏览器不支持HLS");
        return;
      }

      if (hls) {
        hls.destroy();
      }

      hls = new Hls();
      hls.loadSource(m3u8Url);
      hls.attachMedia(videoPlayer);

      hls.on(Hls.Events.MANIFEST_PARSED, () => {
        videoPlayer
          .play()
          .then(() => {
            downloadBtn.disabled = false;
          })
          .catch((error) => {
            console.error("Error playing video:", error);
          });
      });

      hls.on(Hls.Events.ERROR, (event, data) => {
        if (data.fatal) {
          switch (data.type) {
            case Hls.ErrorTypes.NETWORK_ERROR:
              alert("Network error encountered, retrying...");
              hls.startLoad();
              break;
            case Hls.ErrorTypes.MEDIA_ERROR:
              alert("Media error encountered, recovering...");
              hls.recoverMediaError();
              break;
            default:
              hls.destroy();
              break;
          }
        }
      });

      videoPlayer.addEventListener("ended", () => {
        downloadVideo();
      });
    }

    function downloadVideo() {
      const chunks = [];
      const mediaRecorder = new MediaRecorder(videoPlayer.captureStream(), { mimeType: "video/webm" });

      mediaRecorder.ondataavailable = (event) => {
        if (event.data && event.data.size > 0) {
          chunks.push(event.data);
        }
      };

      mediaRecorder.onstop = () => {
        const blob = new Blob(chunks, { type: "video/webm" });
        convertWebmToMp4(blob);
      };

      mediaRecorder.start(1000); // 每秒记录一次

      // 监听视频播放结束
      videoPlayer.addEventListener("ended", () => {
        mediaRecorder.stop();
        hls.destroy(); // 清理 HLS 实例
      });
    }

    function convertWebmToMp4(webmBlob) {
      const arrayBuffer = new Response(webmBlob).arrayBuffer().then((arrayBuffer) => {
        const uint8Array = new Uint8Array(arrayBuffer);

        // 使用 ffmpeg.js 转换
        Module["onRuntimeInitialized"] = async () => {
          await Module.FS_createDataFile("/", "input.webm", uint8Array, true, true, true);
          await Module.run("-i", "input.webm", "-c:v", "libx264", "-c:a", "aac", "output.mp4");
          const mp4Data = Module.FS_readFile("output.mp4");
          const mp4Blob = new Blob([mp4Data.buffer], { type: "video/mp4" });

          // 创建下载链接
          const a = document.createElement("a");
          a.href = URL.createObjectURL(mp4Blob);
          a.download = "output.mp4";
          a.click();
        };
      });
    }
  </script>
</body>
</html>